package com.xch.sboot.config.login;

import com.xch.sboot.common.constant.CachePrefixContant;
import com.xch.sboot.common.constant.RequestHeaders;
import com.xch.sboot.common.exception.BusinessException;
import com.xch.sboot.common.exception.ExceptionEnum;
import com.xch.sboot.service.common.RedisDataService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 登录（token）拦截器
 * @author xch
 * 2022/12/14 14:30
 */
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {

    private RedisDataService redisDataService;

    private LoginProperties loginProperties;

    public LoginInterceptor(RedisDataService redisDataService, LoginProperties loginProperties) {
        this.redisDataService = redisDataService;
        this.loginProperties = loginProperties;
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String requesturi = request.getRequestURI();
        log.info("LoginInterceptor preHandle request URI:{}", requesturi);
        //是不是映射到方法上
        boolean isHandlerMethod = handler instanceof HandlerMethod;
        if(!isHandlerMethod) {
            log.warn("LoginInterceptor preHandle isHandlerMethod:{}", isHandlerMethod);
            return Boolean.TRUE;
        }
        //不需要登录的注解
        boolean noNeedLogin= ((HandlerMethod) handler).getMethodAnnotation(NoNeedLogin.class) != null;
        if(noNeedLogin) {
            return Boolean.TRUE;
        }
        String token = request.getHeader(RequestHeaders.AUTHORIZATION);
        if (StringUtils.isEmpty(token)) {
            log.error("LoginInterceptor preHandle token is empty!");
            throw new BusinessException(ExceptionEnum.UNAUTHORIZED);
        }
        return checkAndRefreshToken(token);
    }

    /**
     * 校验token的有效性，并延期有效时间
     * @param token token
     * @return true校验通过并刷新了token时间
     */
    private synchronized boolean checkAndRefreshToken(String token) {
        String tokenKey = CachePrefixContant.SIGNIN_TOKEN_PREFIX + token;
        boolean hasKey = redisDataService.hasKey(tokenKey);
        if (hasKey) {
            redisDataService.expire(tokenKey, loginProperties.getValidTime());
            return Boolean.TRUE;
        }
        log.error("LoginInterceptor preHandle token:{} is expired!", token);
        throw new BusinessException(ExceptionEnum.UNAUTHORIZED);
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }

}
